/**
 * 将原先根目录下axios.ts文件copy过来， 把它提申为发送请求核心模块
*/

import { AxiosRequestConfig, AxiosPromise, AxiosResponse } from '../types/index';
import xhr from './xhr';
import { buildURL } from '../helpers/url';
import { flattenHeaders } from '../helpers/headers';
import { isAbsoluteURL,combineURL } from '../helpers/util'
import transform  from './transform';

function dispatchRequest(config: AxiosRequestConfig): AxiosPromise {
    throwIfCancelLationRequested(config)
    processConfig(config)
   return xhr(config).then(res => {
     return transformResponseData(res)
   })
}

function processConfig(config: AxiosRequestConfig): void {
  config.url = transformURL(config)
  config.data = transform(config.data, config.headers, config.transformRequest)
  // 合并请求配置后，合并headers
  config.headers = flattenHeaders(config.headers, config.method!)
}

// 处理params
export function transformURL(config: AxiosRequestConfig): string {
  let { url, params, paramsSerializer, baseURL } = config;

  if (baseURL && !isAbsoluteURL(url!)) {
    url = combineURL(baseURL, url)
  }
  // 因为AxiosRequestConfig变为可选属性，此时url可能为undefined
  // 解决方法：url! 感叹号断言： url! 从 url 的类型里去除了 null 和 undefined
//   http://www.zyiz.net/tech/detail-108494.html
  return buildURL(url!, params, paramsSerializer)
}

// 对应响应数据是json字符串： 则转成json对象
// 当请求接口 不设置`responseType`时，返回json字符串
function transformResponseData(res: AxiosResponse): AxiosResponse {
  res.data = transform(res.data, res.headers, res.config.transformResponse)
  return res
}

// 对于： const source = CancelToken.source(); cancelToken: source.token取消方式
// 发送请求前，判断是使用了Cantoken.source.token
// 如果已使用（已调用cancel方法），则不再发送请求
function throwIfCancelLationRequested(config: AxiosRequestConfig):void {
  if(config.cancelToken) {
    config.cancelToken.throwIfRequested()
  }
}

export default dispatchRequest